%%%-------------------------------------------------------------------
%%% File    : p43.erl
%%% Author  : Plamen Dragozov <plamen at dragozov.com>
%%% Description : 
%%% The number, 1406357289, is a 0 to 9 pandigital number because it 
%%% is made up of each of the digits 0 to 9 in some order, but it also 
%%% has a rather interesting sub-string divisibility property.
%%%
%%% Let d_(1) be the 1^(st) digit, d_(2) be the 2^(nd) digit, and so on. 
%%% In this way, we note the following:
%%%
%%%     d_(2)d_(3)d_(4)=406 is divisible by 2
%%%     d_(3)d_(4)d_(5)=063 is divisible by 3
%%%     d_(4)d_(5)d_(6)=635 is divisible by 5
%%%     d_(5)d_(6)d_(7)=357 is divisible by 7
%%%     d_(6)d_(7)d_(8)=572 is divisible by 11
%%%     d_(7)d_(8)d_(9)=728 is divisible by 13
%%%     d_(8)d_(9)d_(10)=289 is divisible by 17
%%%
%%% Find the sum of all 0 to 9 pandigital numbers with this property.
%%% Created : 30 Dec 2008
%%%-------------------------------------------------------------------
-module(p43).

%% API
-compile(export_all).

%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function: 
%% Description:
%%--------------------------------------------------------------------
%A somewhat boring problem, but solving it with lists comprehensions felt really cool (probably not the most optimal solution though).
solution() ->
    Digits = lists:seq(0,9),
    %All 3 digit combinations 
    All = [X*100 + Y *10 + Z|| X<-Digits, Y<-Digits, Z<-Digits, X =/= Y, X =/= Z, Y =/= Z],
    %Lists of all divisible by 2,3,5,7,11,13,17
    L2 = filter(All, 2),
    L3 = filter(All, 3),
    L5 = filter(All, 5),
    L7 = filter(All, 7),
    L11 = filter(All, 11),
    L13 = filter(All, 13),
    L17 = filter(All, 17),
    %Kinda cool, using lists comprehensions to do the job
    Numbers = [[D1|DigitsLast]|| 
	      N2 <- L2, 
              N3 <- L3, 
              N2 rem 100 =:= N3 div 10,%it makes a huge difference for performance to move these guard up
              N5 <- L5, 
              N3 rem 100 =:= N5 div 10,
              N7 <- L7, 
              N5 rem 100 =:= N7 div 10,
              N11 <- L11, 
              N7 rem 100 =:= N11 div 10,
              N13 <- L13, 
              N11 rem 100 =:= N13 div 10,
              N17 <- L17,
              N13 rem 100 =:= N17 div 10,
              DigitsLast <- [[N2 div 100, (N2 rem 100) div 10, N2 rem 10, N3 rem 10 ,N5 rem 10,N7 rem 10, N11 rem 10, N13 rem 10, N17 rem 10]],%last digits of all triplets
              sets:size(sets:from_list(DigitsLast)) =:= 9, %are the last 9 pandigital
              D1 <- lists:seq(0, 9),
              not lists:member(D1, DigitsLast)], % get the missing one for the 1st digit
    ToNumber = fun(L) -> 
                       lists:foldl(fun(D, Acc) -> Acc*10 + D end, 0, L) 
               end,
    lists:sum(lists:map(ToNumber, Numbers)).

%%====================================================================
%% Internal functions
%%====================================================================
%filter out the numbers form L that don't divide by Div.
filter(L, Div) ->
    [X || X<-L, X rem Div =:= 0].
